<?php

namespace addons\yungift\controller;

use addons\yungift\library\Logic;
use addons\yungift\library\Super;
use addons\yungift\model\Activity;
use addons\yungift\model\FundRecord;
use addons\yungift\model\FundUser;
use addons\yungift\model\GiftCode;
use addons\yungift\model\GiftMain;
use addons\yungift\model\GiftOrder;
use addons\yungift\model\GiftSpec;
use addons\yungift\model\Norepeat;
use think\Db;
use think\Exception;
use think\exception\PDOException;
use think\Model;
use think\Validate;

/**
 * 礼品接口
 */
class Gift extends BaseApi
{
    // 获取礼品列表
    public function getList()
    {
        $group = $this->request->post('group');
        $sort = $this->request->post('sort');

        // 数据列表
        $query = GiftMain::where(['status' => GiftMain::STATUS_NORMAL])
            ->where('start_time', ['>', 0], ['<=', time()], 'and')
            ->where('end_time', ['>', 0], ['>', time()], 'and');
        $query->where('find_in_set(:aid, `activity_ids`)', ['aid' => $this->activityId]);
        $query->where('(group_ids is null or group_ids=\'\' or find_in_set(:gid, `group_ids`))',
            ['gid' => $this->memberData->group_id]);
        if ($group === 'gain') {
            $query->order(['count_gain' => $sort, 'weight' => 'DESC', 'id' => 'DESC']);
        } elseif ($group === 'amount') {
            $query->order(['amount' => $sort, 'weight' => 'DESC', 'id' => 'DESC']);
        } else {
            $query->order(['weight' => 'DESC', 'id' => 'DESC']);
        }

        $result = $query->paginate($this->request->post('page_size', 10), false);
        $result = Logic::getPageData($result, [
            'id',
            'type',
            'name',
            'cover_url',
            'worth',
            'amount',
            'multi_spec',
            'count_left',
            'count_gain',
            'created_at',
        ]);

        $this->success('success', $result);
    }


    // 获取礼品详情
    public function getDetail()
    {
        $giftId = $this->request->post('id');
        $gift = $this->validGift($giftId);

        $result = Super::arrayGetSet($gift, [
            'id',
            'type',
            'name',
            'cover_url',
            'photo_list',
            'content',
            'worth',
            'amount',
            'multi_spec',
            'count_left',
            'count_gain',
            'external_link',
            'created_at',
        ]);
        if ($gift->multi_spec) {
            if (! $giftSpecList = $gift->giftSpecListData) {
                $this->error('礼品数据无效，缺少规格');
            }
            $result['spec_list'] = Super::arrayGetSet($giftSpecList, [
                'id',
                'name',
                'worth',
                'amount',
                'count_left',
                'count_gain'
            ], true);
            $result['order_amount'] = $giftSpecList[0]->amount;
            $result['order_worth'] = $giftSpecList[0]->worth;
        } else {
            $result['spec_list'] = null;
            $result['order_amount'] = $gift->amount;
            $result['order_worth'] = $gift->worth;
        }

        // 兑换状态
        $orderState = 0;  // 正常状态
        if ($this->activityData->state == Activity::STATE_READY) {
            $orderState = 1;  // 兑换未开始
        } elseif ($this->activityData->state == Activity::STATE_END) {
            $orderState = 2;  // 兑换已结束
        } elseif ($gift->count_left <= 0) {
            $orderState = 3;  // 库存不足
        } else {
            if (! $fundUser = FundUser::get(['activity_id' => $this->activityId, 'member_id' => $this->memberId])) {
                $this->error('礼币账户未激活，请联系管理员处理');
            }
            if ($fundUser->status != FundUser::STATUS_NORMAL) {
                $orderState = 4;  // 礼币账户被禁用
            } elseif ($fundUser->amount_left < $result['order_amount']) {
                $orderState = 5;  // 礼币不足
            } elseif (isset($result['spec_list']) && $result['spec_list'][0]['count_left'] <= 0) {
                $orderState = 3;
            }
        }
        $result['order_state'] = $orderState;

        $this->success('success', $result);
    }

    // 兑换预览
    public function getPreview()
    {
        $giftId = $this->request->post('gift_id');
        $specId = $this->request->post('gift_spec_id');
        $gift = $this->validGift($giftId);
        if ($this->activityData->state != Activity::STATE_ING) {
            $this->error('活动未开启或已结束');
        }

        $result['gift_data'] = Super::arrayGetSet($gift, [
            'id',
            'type',
            'name',
            'cover_url',
            'worth',
            'amount',
            'count_left',
            'count_gain',
            'gain_methods',
            'offline_place',
            'external_link'
        ]);
        $amount = $gift->amount;
        if ($giftSpec = GiftSpec::get($specId)) {
            if ($giftSpec->gift_id != $giftId) {
                $this->error('规格不存在');
            }
            $amount = $giftSpec->amount;
            $result['gift_data']['spec_data'] = Super::arrayGetSet($giftSpec, ['id', 'name', 'worth', 'amount']);
            $result['gift_data']['order_amount'] = $giftSpec->amount;
            $result['gift_data']['order_worth'] = $giftSpec->worth;
        } else {
            $result['gift_data']['order_amount'] = $gift->amount;
            $result['gift_data']['order_worth'] = $gift->worth;
        }

        if (! $fundUser = FundUser::get(['activity_id' => $this->activityId, 'member_id' => $this->memberId])) {
            $this->error('礼币账户未激活，请联系管理员处理');
        }
        if ($fundUser->status != FundUser::STATUS_NORMAL) {
            $this->error(__('礼币账户被禁用，请联系管理员处理'));
        }
        $result['fund_data'] = ['amount_left' => $fundUser->amount_left];  // 剩余礼币
        $result['order_data'] = ['amount' => $amount];  // 应付礼币

        $this->success('success', $result);
    }

    // 兑换礼品
    public function exchange()
    {
        // 参数校验
        $data = $this->request->post();
        $validate = new Validate([
            'gift_id' => 'require',
            'amount'  => 'require',
        ]);
        if (! $validate->check($data)) {
            $this->error($validate->getError());
        }
        $giftId = $data['gift_id'];
        $gift = $this->validGift($giftId);
        if ($this->activityData->state != Activity::STATE_ING) {
            $this->error('活动未开启或已结束');
        }
        if (! $fundUser = FundUser::get(['activity_id' => $this->activityId, 'member_id' => $this->memberId])) {
            $this->error('礼币账户未激活，请联系管理员处理');
        }
        if ($fundUser->status != FundUser::STATUS_NORMAL) {
            $this->error(__('礼币账户被禁用，请联系管理员处理'));
        }

        $giftData = Super::arrayGetSet($gift, [
            'id',
            'name',
            'cover_url' => function ($item) {
                return $item->getData('cover_url');
            },
            'type',
            'type_text',
            'worth',
            'amount',
            'offline_place',
            'external_link'
        ]);

        // 校验领取方式
        $gainMethod = $data['gain_method'] ?? 0;
        if ($gift['type'] == GiftMain::TYPE_1) {
            if ($gainMethod == 0) {
                $this->error('领取方式未填写');
            }
            if ($gainMethod == GiftOrder::GAIN_METHOD_EXPRESS) {
                if (empty($data['address'])) {
                    $this->error('收货地址未填写');
                }
            } elseif ($gainMethod != GiftOrder::GAIN_METHOD_SELF) {
                $this->error('领取方式无效');
            }
        } else {
            $data['gain_method'] = GiftOrder::GAIN_METHOD_NONE;
        }

        // 校验商品库存
        if ($gift->count_left <= 0) {
            $this->error('库存不足');
        }
        $costAmount = $gift->amount;

        // 校验规格库存
        $giftSpec = null;
        if ($giftSpecId = $data['gift_spec_id']) {
            if (! $gift->multi_spec) {
                $this->error('无需指定规格');
            }
            if (! $giftSpec = GiftSpec::get(['id' => $giftSpecId, 'gift_id' => $gift->id])) {
                $this->error('礼品规格不存在');
            }
            if ($giftSpec->count_left <= 0) {
                $this->error('库存不足');
            }
            if ($giftSpec->amount) {
                $costAmount = $giftSpec->amount;
            }
            $giftData['spec_data'] = Super::arrayGetSet($giftSpec, ['id', 'name', 'worth', 'amount']);
            $giftData['order_amount'] = $giftSpec->amount;
            $giftData['order_worth'] = $giftSpec->worth;
        } else {
            if ($gift->multi_spec) {
                $this->error('还未选择规格');
            }
            $giftData['order_amount'] = $gift->amount;
            $giftData['order_worth'] = $gift->worth;
        }

        // 校验兑换礼币
        if ($costAmount != $data['amount']) {
            $this->error('兑换礼币不一致');
        }

        // 兑换次数的限制
        $gainTimes = 1;
        if ($gift->limit_user) {
            $gainTimes = GiftOrder::where([
                'gift_id'    => $gift->id,
                'type'       => GiftOrder::TYPE_ACTIVITY,
                'account_id' => $fundUser->id
            ])->count();
            if ($gainTimes >= $gift->limit_user) {
                $this->error('当前礼品已达到兑换次数的限制');
            }
        }


        // 增加订单
        $giftOrder = new GiftOrder();
        $giftOrder->data(Super::arrayGetSet($data, [
            'gain_method',
            'name',
            'phone',
            'province',
            'city',
            'area',
            'address',
            'note',
            'gift_id',
            'gift_spec_id',
            'amount'
        ]));
        $giftOrder['type'] = GiftOrder::TYPE_ACTIVITY;
        $giftOrder->model_id = $this->activityId;
        $giftOrder->account_id = $fundUser->id;
        $giftOrder->member_id = $this->memberId;


        // 发放券码
        $giftCode = null;
        if ($gift['type'] == GiftMain::TYPE_2) {
            $where = ['gift_id' => $gift->id, 'status' => GiftCode::STATUS_NORMAL];
            if ($giftSpec) {
                $where['gift_spec_id'] = $giftSpec->id;
            } else {
                $where['gift_spec_id'] = 0;
            }
            if (! $giftCode = GiftCode::where($where)->orderRaw('rand()')->find()) {
                $this->error('礼品已领取完');
            }
            // 标记已使用
            $giftCode->status = GiftCode::STATUS_GAINED;
            $giftOrder->gift_code_id = $giftCode->id;
            $giftOrder->status = GiftOrder::STATUS_HAS_DEPLOY;
            $giftOrder->deployed_at = time();
            $giftData['code_data'] = Super::arrayGetSet($giftCode, ['id', 'data']);
        } else {
            $giftOrder->status = GiftOrder::STATUS_WAIT_DEPLOY;
        }
        $giftOrder->gift_data = json_encode($giftData);
        $giftOrder->gift_type = $gift['type'];
        $giftOrder->gift_amount = $giftData['order_amount'];

        // 事务处理
        try {
            Db::transaction(function () use ($gift, $giftSpec, $giftCode, $giftOrder, $gainTimes) {
                // 防重校验
                if ($gift->limit_user) {
                    Norepeat::tryAddData('gift:gain_times',
                        $gift->id . ':' . $giftOrder->member_id . ':' . $gainTimes . ':' . date('ymdHi'));
                }

                // 更新商品库存
                Logic::niceAssert(GiftMain::where(['id' => $gift->id])->where('count_left', '>', 0)
                    ->update(['count_left' => Db::raw('count_left-1'), 'count_gain' => Db::raw('count_gain+1')]),
                    '库存不足');

                // 更新规格库存
                if ($giftSpec) {
                    Logic::niceAssert(GiftSpec::where(['id' => $giftSpec->id])->where('count_left', '>', 0)
                        ->update(['count_left' => Db::raw('count_left-1'), 'count_gain' => Db::raw('count_gain+1')]),
                        '库存不足');
                }

                // 标记code
                if ($giftCode) {
                    Logic::niceAssert(GiftCode::where(['id' => $giftCode->id])->where(['status' => GiftCode::STATUS_NORMAL])
                        ->update(['status' => GiftCode::STATUS_GAINED]), '领取失败，请稍后再试');
                }

                // 增加订单
                $giftOrder->save();
                $giftOrder->number = 'NYX' . date('ymd') . str_pad($giftOrder->id, 8, '0', STR_PAD_LEFT);  // 订单编号
                $giftOrder->save();

                // 扣减积分
                FundUser::amountCounter($giftOrder->model_id, $giftOrder->member_id,
                    FundRecord::ACTION_GIFT_EXCHANGE,
                    -$giftOrder->amount, Logic::SOURCE_GIFT_RECORD, $giftOrder->id,
                    Logic::SOURCE_GIFT, $giftOrder->gift_id);
            });
            Logic::sendExchangeMessage($giftOrder->id);  // 发送兑换消息
        } catch (Exception $e) {
            $this->error($e->getMessage());
        }

        $this->success('success', ['id' => $giftOrder->id]);
    }

    // 获取兑换列表
    public function getOrderList()
    {
        $group = $this->request->post('group');

        // 数据列表
        $query = GiftOrder::where([
            'type'      => GiftOrder::TYPE_ACTIVITY,
            'model_id'  => $this->activityId,
            'member_id' => $this->memberId
        ])
            ->order('id DESC');
        if ($group) {
            $query->where(['status' => $group]);
        }
        $result = $query->paginate($this->request->post('page_size', 10), false);
        $result = Logic::getPageData($result, [
            'id',
            'number',
            'gift_data'   => 'giftDataArray',
            'gain_method',
            'amount',
            'status',
            'status_text' => 'statusText',
            'created_at',
        ]);

        $this->success('success', $result);
    }


    // 获取兑换详情
    public function getOrderDetail()
    {
        $orderId = $this->request->post('id');
        if (! $giftOrder = GiftOrder::get([
            'id'        => $orderId,
            'model_id'  => $this->activityId,
            'member_id' => $this->memberId
        ])) {
            $this->error('订单不存在');
        }

        $result = Super::arrayGetSet($giftOrder, [
            'id',
            'number',
            'gift_data'    => 'giftDataArray',
            'gain_method',
            'name',
            'phone',
            'address_data' => function ($item) {
                if ($item->gain_method != GiftOrder::GAIN_METHOD_EXPRESS) {
                    return null;
                }
                $giftData = $item->giftDataArray;
                if ($giftData['type'] != GiftMain::TYPE_1) {
                    return null;
                }

                return Super::arrayGetSet($item, ['name', 'phone', 'province', 'city', 'area', 'address']);
            },
            'express_data' => function ($item) {
                if ($item->gain_method != GiftOrder::GAIN_METHOD_EXPRESS) {
                    return null;
                }
                $giftData = $item->giftDataArray;
                if ($giftData['type'] != GiftMain::TYPE_1) {
                    return null;
                }
                if ($item->status != GiftOrder::STATUS_HAS_DEPLOY) {
                    return null;
                }

                return [
                    'company'     => $item->express_company_text,
                    'number'      => $item->express_number,
                    'deployed_at' => $item->deployed_at
                ];
            },
            'amount',
            'note',
            'status',
            'status_text'  => 'statusText',
            'deployed_at',
            'created_at',
        ]);

        $this->success('success', $result);
    }

    // 获取物流动态
    public function getExpressFeed()
    {
        $giftId = $this->request->post('id');
        if (! $giftOrder = GiftOrder::get([
            'id'        => $giftId,
            'model_id'  => $this->activityId,
            'member_id' => $this->memberId
        ])) {
            $this->error('订单不存在');
        }

        try {
            $result = Logic::queryExpressTrack($giftOrder->express_company, $giftOrder->express_number,
                $giftOrder->express_phone);
        } catch (Exception $e) {
            $this->error($e->getMessage());
        }
        $result['address'] = $giftOrder['province'] . $giftOrder['city'] . $giftOrder['area'] . $giftOrder['address'];
        $result['deployed_at'] = $giftOrder->deployed_at;
        $result['company'] = $giftOrder->expressCompanyText;

        $this->success('success', $result);
    }

    // 订单取消
    public function orderCancel()
    {
        $orderId = $this->request->post('order_id');

        Db::startTrans();
        try {
            // 订单数据
            $giftOrder = GiftOrder::where([
                'id'        => $orderId,
                'model_id'  => $this->activityId,
                'member_id' => $this->memberId
            ])->lock(true)->find();
            if (! $giftOrder) {
                $this->error('订单不存在');
            }
            if ($giftOrder->status != GiftOrder::STATUS_WAIT_DEPLOY) {
                $this->error('只支持取消待发货订单');
            }

            // 商品类型
            $giftData = $giftOrder->giftDataArray;
            if ($giftData['type'] != GiftMain::TYPE_1) {
                $this->error('只支持取消兑换实物订单');
            }

            // 更新订单状态
            $giftOrder->status = GiftOrder::STATUS_HAS_BACK;
            $giftOrder->save();

            // 退回礼品库存
            $gift = GiftMain::get(['id' => $giftOrder->gift_id]);
            if (! $gift || $gift['type'] != $giftData['type'] || ($gift->multi_spec && ! $giftOrder->gift_spec_id)) {
                throw new Exception($giftData['name'] . '礼品变更过，不能进行取消退回');
            }
            GiftMain::where(['id' => $gift->id])->inc('count_left')->dec('count_gain')->update();

            // 退回礼品规格库存
            if ($giftOrder->gift_spec_id) {
                if (! $giftSpec = GiftSpec::get(['id' => $giftOrder->gift_spec_id])) {
                    throw new Exception($giftData['spec_data']['name'] . '规格被删除，不能进行取消退回');
                }
                GiftSpec::where(['id' => $giftSpec->id])->inc('count_left')->dec('count_gain')->update();
            }

            // 操作礼币
            FundUser::amountCounter($giftOrder->model_id, $giftOrder->member_id, FundRecord::ACTION_GIFT_BACK,
                $giftOrder->amount, Logic::SOURCE_GIFT_RECORD, $giftOrder->id, $giftOrder->account_id);
            Db::commit();
        } catch (PDOException | Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }

        $this->success('success', []);
    }

    /**
     * 校验礼品
     *
     * @param $giftId
     * @return GiftMain
     */
    private function validGift($giftId)
    {
        if (! $gift = GiftMain::get($giftId)) {
            $this->error('礼品无效');
        }
        if ($gift->status != GiftMain::STATUS_NORMAL) {
            $this->error('礼品已下架');
        }
        if (($gift->start_time && $gift->start_time > time()) || ($gift->end_time && $gift->end_time <= time())) {
            $this->error('礼品已下架');
        }

        $activityIds = $gift->activity_ids ? explode(',', $gift->activity_ids) : [];
        if (! in_array($this->activityId, $activityIds)) {
            $this->error('没有兑换权限');
        }
        if ($gift->group_ids) {
            $groupIds = explode(',', $gift->group_ids);
            if (! in_array($this->memberData->group_id, $groupIds)) {
                $this->error('没有兑换权限');
            }
        }

        return $gift;
    }
}
